<?php
/**
 * @author Robert Hahn
 * @version 02/21/2011
 * 
 * An Ajax Helper fo JQUERY
 * JQuery is ABSOLUTELY REQUIRED
 * 
 * USAGE
 * call the "show()" method on the end of all your layouts to return the ajax calls created by the other methods
 * 
 *
 */
class SnapajaxHelper extends AppHelper	{
	
	var $helpers = array("Javascript", "Html", "Form");
	private $functions = array();
	
	private function quote($str)	{
		return "'$str'";
	}
	
	/**
	 * 
	 * used by all other methods - creates an ajax request
	 * @param array $settings some settings (url, dataType); same paramNames as used by jQuery ajax()
	 * @return string javascript function name which must be called to run the ajax request
	 */
	public function remoteFunction($settings=array())	{
		if (!isset($settings['url'])) return;
		$settings['url'] = $this->url( $settings['url'] );
		 
		if (isset($settings['success']) && !is_array($settings['success']))	{
			$settings['success'] = array($settings['success']);
		}
		
		if (isset($settings['validate']) && $settings['validate'])	{
			if (!isset($settings['success'])) $settings['success'] = array();
			array_unshift($settings['success'], 'ajax_form_validation');
		}
		
		if (!isset($settings['type'])) $settings['type'] = "POST";
		
		$paramString = "";
		if (!isset($settings['with']))
			$settings['with'] = array();
		if (isset($settings['with']))	{ // ajax parameters
			$settings['with']["ajax"] = "true";
			if (isset($settings['validate']) && $settings['validate'])
				$settings['with']['validate'] = "true";
			$i = 0;
			foreach($settings['with'] as $param => $value)	{
				$i++;
				if (strpos($value, "js:") === 0 )	{ // javascript
					$value = str_replace("js:", "", $value);
					if (count($settings['with']) > $i) $value .= "+'&'";
					$paramString .= "'$param='+$value";
				} else {
					if (count($settings['with']) > $i) $value .= "&";
					$paramString .= "'$param=$value'";
				}	
				if (count($settings['with']) > $i)	{ // it wasnt the last param
					$paramString .= "+";
				}
			}
			if (isset($settings['form']))	{ // form
				$paramString .= "+'&'+jQuery(form).serialize()+'&form_id='+jQuery(form).attr('id')";		
			}
			$paramString = str_replace("'+'", "", $paramString);
			
		}
		$settings['with'] = $paramString;
		
		$ajaxRequest = "jQuery.ajax({url: {$this->quote($settings['url'])}, type: {$this->quote($settings['type'])}";
		
		if ($settings['with'] != "")
			$ajaxRequest .= ", data: {$settings['with']}";
		if (isset($settings['success']) || isset($settings['update']))	{
			$ajaxRequest .= ", success: function(data){ ";
			if (isset($settings['update']))	{
				$selector = $settings['update'];
				if (strpos($selector, "#") !== 0 && strpos($selector, ".") !== 0 && strpos($selector, "[") !== 0 && strpos($selector, "$") !== 0)
					$selector = "#$selector";
				if (isset($settings['dataType']) && $settings['dataType'] == 'json')	{
					$dummy = $settings['dummy'];
					if (strpos($dummy, "#") !== 0 && strpos($dummy, ".") !== 0 && strpos($dummy, "[") !== 0)
						$dummy = "#$dummy";
					$ajaxRequest .= " new JsonToHtml( data, '$dummy', '$selector');";
				}	
				if (!isset($settings['dataType']) || $settings['dataType'] != 'json')	{
					if (strpos($settings['update'], "$") !== 0)
						$ajaxRequest .= " jQuery('$selector').html( data );";
					else $ajaxRequest .= " $selector.html( data );";
				}
			}
			if (isset($settings['success']))
				foreach($settings['success'] as $k => $func)	{
					if ($func == 'ajax_form_validation')
						$ajaxRequest .= " if (!{$func}(data)) return false;";
					else $ajaxRequest .= " {$func}(data);";
				}
			$ajaxRequest .= " }";
		}
		if (isset($settings['async']))	{
			$settings['async'] = $settings['async']?"true":"false";
			$ajaxRequest .= ", async: {$settings['async']} ";
		}
		if (isset($settings['dataType']))	{
			$ajaxRequest .= ", dataType: {$this->quote($settings['dataType'])} ";
		}
		$ajaxRequest .= "});";
		return $this->createFunction( $ajaxRequest, $settings );
	}
	
	/**
	 * should enable you a fast json request
	 */
	public function json($settings)	{
		$settings['dataType'] = 'json';
		return $this->remoteFunction($settings);
	}
	
	/**
	 * 
	 * creates an submit element and sends the form-data by serializing the parent form
	 * @param string $title submitbutton title
	 * @param array $settings
	 * @return string same as Form->submit() wood do
	 */
	public function submit($title, $settings=array())	{
		$settings['form'] = true;
		$funcName = $this->remoteFunction($settings);
		unset($settings['settings']);unset($settings['form']);
		$settings['onclick'] = $funcName;
		return $this->Form->submit($title, $settings);
	}
	
	/**
	 * 
	 * returns an link created by Html->link
	 * @param string $title link title
	 * @param array $url
	 * @param array $settings
	 * @return string same as Html->link wood do
	 */
	public function link($title, $url, $settings=array())	{
		$settings['url'] = $url;
		$settings['link'] = true;
		$funcName = $this->remoteFunction($settings);
		unset($settings['settings']);unset($settings['link']);unset($settings['url']);unset($settings['success']);
		if (!isset($settings['onclick'])) $settings['onclick'] = $funcName;
		else $settings['onclick'] .= $funcName;
		return $this->Html->link($title, $url, $settings);
	}
	
	private function createFunction($evalString, $settings=array() )	{
		$name = "ajax_".md5( time().mt_rand().mt_rand() );
		$params = "";
		if (isset($settings['form'])) 	{
			$params .= "form";
		}
		$this->functions[] = "function $name($params) { $evalString }";
		if (isset($settings['form']))
			return "$name( jQuery(this).parents('form').first() ); return false;";
		if (isset($settings['link'])) 
			return "$name(); return false;";
		return "$name();";
	}
	
	/**
	 * 
	 * REALLY IMPORTANT
	 * call this function in EVERY LAYOUT WHICH CAN RETURN Ajax Calls
	 * @return JavaScript Codeblock including ALL Ajax-Call-Functions
	 */
	public function show()	{
		if (count($this->functions) > 0)	{
			foreach($this->functions as $i => $func)
			print $this->Javascript->codeBlock($func);
		}
	}
}